
#include "logreader.h"
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

LogReader::LogReader()
{
}

LogReader::~LogReader()
{
}

/* 按顺序调用5个功能函数 */
list<MatchedLogRec> LogReader::readLogs()
{
	cout<<"开始读取日志"<<endl;
	backup();
	readFailLogins();
	readBackupFile();
	matchLogRec();
	saveFailLogins();

	return matches;
}

void LogReader::backup()
{
	cout<<"1. back up log file"<<endl;
	sprintf(backFileName,"wtmpx");
}

void LogReader::readFailLogins()
{
	cout<<"2.read fail logins file"<<endl;
}

void LogReader::readBackupFile()
{
	cout<<"3.read backup log file"<<endl;
	/* 
	 *	读取备份好的日志文件，把日志文件中的数据读出来
	 *	封装成LogRec 对象， 把用户名是 . 开头的过滤掉
	 *	把logtype 是7的放入logins
	 *	把logtype 是8的放入logouts
	 *	日志文件时在unix下生成的
	 * */
	/* 先得到文件的大小 */
	int fd = open(backFileName, O_RDONLY);
	if(fd == -1)
		perror("open log file failed"), exit(-1);

	struct stat flog = {0};
	fstat(fd, &flog);
	cout<<"日志文件的大小为:"<<flog.st_size/372;
	int count = flog.st_size/372;

	LogRec log;
	int i;
	for(i=0; i<count; i++)
	{
		read(fd, &log.logname, 32);
		lseek(fd, 36, SEEK_CUR);
		read(fd,&log.pid, 4);
		log.pid = htonl(log.pid);
		read(fd, &log.logtype, 2);
		log.logtype = htons(log.logtype);
		lseek(fd, 6, SEEK_CUR);
		read(fd, &log.logtime, 4);
		log.logtime = htonl(log.logtime);
		lseek(fd, 30, SEEK_CUR);
		read(fd, &log.logip, 257);
		lseek(fd, 1, SEEK_CUR);
		cout<<log.logname<<":"<<log.logtype<<endl;

		/* 把 . 开头的名字过滤掉 */
		if(log.logname[0] != '.')
		{
			if(log.logtype == 7)	
				logins.push_back(log);
			else if (log.logtype == 8)
				logouts.push_back(log);
		}
	}
	close(fd);
}

void LogReader::matchLogRec()
{
	cout<<"4.match log rec"<<endl;
}

void LogReader::saveFailLogins()
{
	cout<<"5.save fail logins"<<endl;
	/* 
	 *	1.从登出集合中循环取出一条记录
	 *	2.在登入集合中循环查找
	 *	3.找到匹配记录就构造匹配记录，加入匹配集合 删除登入记录 中断本次循环
	 *	4.如果本次没找到 继续查找 知道查找结束
	 *	5.清空登出集合
	 * */
	list<LogRec>::iterator oit;
	list<LogRec>::iterator iit;
	/* 使用迭代器循环从登出集合中取出数据 */
	for(oit=logouts.begin(); oit != logouts.end(); oit++)
	{
		iit = logins.begin();	
		while(iit != logins.end())
		{
			if(!strcmp(iit->logname, oit->logname) && 
					iit->pid == oit->pid &&
					!strcmp(iit->logip, oit->logip))	
			{
				MatchedLogRec mlog;	
				/* 赋值 */
				sprintf(mlog.logname, iit->logname);
				mlog.pid = iit->pid;
				mlog.logintime = iit->logtime;
				mlog.logouttime = oit->logtime;
				mlog.durations = mlog.logouttime - mlog.logintime;
				sprintf(mlog.logip, iit->logip);
				matches.push_back(mlog);
				logins.erase(iit);
				break;
			}
			iit++;
		}
	}
	logouts.clear();
}

/* 
char	logFileName[50];
char	backFileName[50];
char	failLoginFile[50];
list<LogRec> logins;
list<LogRec> logouts;
list<MatchedLogRec> matches;
*/
